#pragma once

#include "glm/glm.hpp"
#include "glm/ext.hpp"
using namespace glm;
struct Frustrum
{
	vec3 top_left_position;
	vec3 top_left_direction;
};

inline mat4x4 view_matrix(vec3 eye, vec3 focus, vec3 up)
{
	return lookAt(eye, focus, up);
}

inline mat4x4 proj_matrix(float w, float h)
{
	float ar = w/h;
	return perspective(45.0f, ar, 1.0f, 1000.0f);
}

inline vec3 delta_position_per_pixel(float fov, float aspect_ratio, float z_near, float z_far, vec2 viewport_size)
{
	vec3 offset;
	float k = tan(radians(fov) / 2);
	offset.x = aspect_ratio * 2 * z_near * k / viewport_size.x;
	offset.y = -2 * z_near * k / viewport_size.y;
	offset.z = 0;
	return offset;
}
inline vec3 screen_to_world(vec2 p, float z, vec2 viewport, const mat4x4& inv_viewproj)
{
	vec2 np = ((p / viewport) - vec2(0.5)) * vec2(2, -2);
	vec4 wp = inv_viewproj * vec4(np, z, 1);
	return vec3(wp) / wp.w;
}

inline Frustrum frustrum(const mat4x4& proj, const vec2& viewport)
{
	Frustrum frustrum;	
	auto inv_proj = inverse(proj);
	auto p1 = screen_to_world(vec2(0, 0), -1, viewport, inv_proj);
	auto p2 = screen_to_world(vec2(0, 0), 1, viewport, inv_proj);
	frustrum.top_left_position = p1;
	frustrum.top_left_direction = normalize(p2 - p1);
	return frustrum;
}
